/*	Interactive Gravitational Simulator
	Project: IGS Core
	File: CompositeModel.cpp
	Author: Mike Bantegui <mbante2@gmail.com>, Hofstra University 
	Copyright (C) 2012 - 2013 Mike Bantegui

	This file is part of the IGS software package for simulating
	the N-Body problem in real-time. This was developed as part
	of a departmental honors thesis project at Hofstra University
	in the Spring 2012 semester.

	IGS is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 2 of the License, or
	(at your option) any later version.

	IGS is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program; if not, write to the Free Software
	Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/

#include "Body.h"
#include "CompositeModel.h"
#include "NBodySystem.h"
#include <cassert>

namespace IGS
{

struct CompositeModel::Component
{
	Model *Model;
	const Vector Position;
	const Vector Velocity;
	const int Size;
};


// Destructs the CompositeModel
CompositeModel::~CompositeModel()
{
	for (size_t i = 0; i < Models.size(); i++)
		delete Models[i].Model;
}

// Adds a component to the CompositeModel
void CompositeModel::AddComponent(Model *model, const Vector &position, 
	const Vector &velocity, const int size)
{
	assert(model != NULL);
	assert(size > 0);

	const Component c = { model, position, velocity, size };
	Models.push_back(c);
}

// Creates a system of N bodies in a composite configuration
void CompositeModel::Fill(Body *bodies, const int N)
{
	int total = 0;
	for (size_t i = 0; i < Models.size(); i++)
		total += Models[i].Size;

	int start = 0;
	int remaining = N;

	for (size_t i = 0; i < Models.size(); i++)
	{
		const Component &c = Models[i];

		const double fraction = c.Size / (double) total;
		int amount = (int)(fraction * N);

		// Handle extra bodies at the end
		remaining -= amount;
		if (i == Models.size() - 1 && remaining > 0)
			amount += remaining;

		Models[i].Model->Fill(&bodies[start], amount);

		// Translate the body positions and velocities
		for (int i = start; i < start + amount; i++)
		{
			bodies[i].Position += c.Position;
			bodies[i].Velocity += c.Velocity;
		}

		start += amount;
	}

	assert(start == N);
}

}
